#ifndef __AST_H__
#define __AST_H__

#include "base.h"
#include "src.h"
#include "token.h"

enum nodeKind 
{
	NK_None,
	NK_TranslationUnit,     NK_Function,           NK_Declaration,
	NK_TypeName,            NK_Specifiers,         NK_Token,				
	NK_TypedefName,         NK_EnumSpecifier,      NK_Enumerator,			
	NK_StructSpecifier,     NK_UnionSpecifier,     NK_StructDeclaration,	
	NK_StructDeclarator,    NK_PointerDeclarator,  NK_ArrayDeclarator,		
	NK_FunctionDeclarator,  NK_ParameterTypeList,  NK_ParameterDeclaration,
	NK_NameDeclarator,      NK_InitDeclarator,     NK_Initializer,
	
	NK_Expression,

	NK_ExpressionStatement, NK_LabelStatement,     NK_CaseStatement,		
	NK_DefaultStatement,    NK_IfStatement,        NK_SwitchStatement,		
	NK_WhileStatement,      NK_DoStatement,        NK_ForStatement,		
	NK_GotoStatement,       NK_BreakStatement,     NK_ContinueStatement,		
	NK_ReturnStatement,     NK_CompoundStatement,
	NK_Print,
	NK_Import,
	NK_METHOD,
	NK_Class,
	NK_Global,
	NK_StatementEnd,
};

typedef struct ast_node_t ast_node_t;
struct ast_node_t
{
    int kind = 0;
    ast_node_t *parent = nullptr;
    ast_node_t *prev = nullptr;
    ast_node_t *next = nullptr;
    location_t loc;
    token_t token;
};

struct ast_t
{
	struct buffer_t* buf = nullptr;
    ast_node_t* nodes = nullptr;
	~ast_t();
};

int parser_ast(ast_t* ast, const char* buffer, int size, const char* filename/* = NULL */);

void append_node(ast_node_t** root, ast_node_t* node);

void remove_node(ast_node_t** root, ast_node_t* node);

int count_node(ast_node_t* node);

void free_node(ast_node_t* node);

void free_nodes(ast_node_t* node);

int ast_count(ast_t* ast);

void dump_ast(ast_t* ast);

void do_print_node(ast_node_t* node, int tab, bool s);

void print_node(ast_node_t* node);

void print_node_s(ast_node_t* node);

extern token_t tokc;    // current token

token_t next_token();

void token_next();

int get_ast_error_count();

ast_node_t* get_ast_errors();

void free_ast_errors();

void do_warning(location_t* loc, const char *format, ...);

void do_error(location_t* loc, const char *format, ...);

void expect_token(token_e token);

/**
 * Check if current token is in a token set
 */
int current_token_in(int toks[]);

bool is_decl(ast_node_t* node);

ast_node_t* parse_node();

#endif  // __AST_H__
